package fr.castorflex.ohos.verticalviewpager;

import fr.castorflex.ohos.verticalviewpager.transformer.MathUtils;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.PageSlider;
import ohos.app.Context;

import java.util.List;

/**
 * 扩展了PageSlide的动画接口
 *
 * @author stt
 * @since 2021-04-26
 */
public class VerticalViewPager extends PageSlider implements PageSlider.PageChangedListener {
    private static final int SLID_LEFT = 0;
    private static final int SLID_LEFT_ELASTIC = 1;
    private static final int SLID_RIGHT = 2;
    private static final int SLID_RIGHT_ELASTIC = 3;
    private static final int SLID_NONE = 4;
    private static final int SCROLL_RIGHT = -1;
    private int mCurrentState = 0;
    private int mItemPosOffsetPixels = 0;
    private int mLastScrollState;
    private float mItemPosOffset = 0;
    private float mOriginalOffset = 0;
    private List<Component> mComponents;
    private VerticalViewPager.PageTransformer mPageTransformer;

    /**
     * 此类为了适配PageSlide滑动监听参数问题
     *
     * @param context context
     */
    public VerticalViewPager(Context context) {
        this(context, null);
    }

    /**
     * 此类为了适配PageSlide滑动监听参数问题
     *
     * @param context context
     * @param attrSet attrSet
     */
    public VerticalViewPager(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
        addPageChangedListener(this);
    }

    /**
     * 此类为了适配PageSlide滑动监听参数问题
     *
     * @param context context
     * @param attrSet attrSet
     * @param styleName style name
     */
    public VerticalViewPager(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
    }

    @Override
    public void onPageSliding(int position, float offset, int offsetPixels) {
        onPageScrolled(position, offset, offsetPixels);
    }

    @Override
    public void onPageSlideStateChanged(int state) {
        mCurrentState = state;
    }

    @Override
    public void onPageChosen(int i) {
        // NOTHING
    }

    /**
     * 设置PageSlide所有子组件
     *
     * @param components 子组件集合
     */
    public void setPages(List<Component> components) {
        this.mComponents = components;
    }

    /**
     * 设置动画接口
     *
     * @param pageTransformer 动画接口实现类
     */
    public void setPageTransformer(VerticalViewPager.PageTransformer pageTransformer) {
        this.mPageTransformer = pageTransformer;
    }

    private void onPageScrolled(int position, float offset, int offsetPixels) {
        if (mPageTransformer != null) {
            onPageTransformer(position, offset, offsetPixels);
        }
    }

    private void onPageTransformer(int position, float positionOffset, int offsetPixels) {
        mOriginalOffset = positionOffset;
        this.mItemPosOffset = positionOffset;
        this.mItemPosOffsetPixels = offsetPixels;

        int realSlidState = getRealSlidState();
        if (realSlidState != SLID_NONE) {
            mLastScrollState = realSlidState;
        }
        switch (mLastScrollState) {
            case SLID_LEFT:
                scrollLeft(position, positionOffset);
                break;
            case SLID_RIGHT:
                scrollRight(position, positionOffset);
                break;
            case SLID_LEFT_ELASTIC:
                // 向左滑动但未达到临界回弹
                elasticLeft(position, positionOffset);
                break;
            case SLID_RIGHT_ELASTIC:
                // 向右滑动但未达到临界回弹
                elasticRight(position, positionOffset);
                break;
            default:
                break;
        }
    }

    private void elasticLeft(int position, float positionOffset) {
        if(position >= mComponents.size() - 1) {
            return;
        }
        Component in = mComponents.get(position);
        Component out = mComponents.get(position + 1);
        mPageTransformer.transformPage(out, mOriginalOffset);
        mPageTransformer.transformPage(in, MathUtils.floatToAdd(SCROLL_RIGHT, positionOffset));
    }

    private void elasticRight(int position, float positionOffset) {
        if(position < 1) {
            return;
        }
        Component out = mComponents.get(position - 1);
        Component in = mComponents.get(position);
        mPageTransformer.transformPage(in, MathUtils.floatToSubtract(1, positionOffset));
        mPageTransformer.transformPage(out, MathUtils.floatToSubtract(0, positionOffset));
    }

    private void scrollRight(int position, float positionOffset) {
        if(position < 1) {
            return;
        }
        // 从左往右滑动
        Component in = mComponents.get(position - 1);
        Component out = mComponents.get(position);
        mPageTransformer.transformPage(out, mOriginalOffset);
        mPageTransformer.transformPage(in, MathUtils.floatToAdd(SCROLL_RIGHT, positionOffset));
    }

    private void scrollLeft(int position, float positionOffset) {
        if(position >= mComponents.size() - 1) {
            return;
        }
        Component in = mComponents.get(position + 1);
        Component out = mComponents.get(position);
        mPageTransformer.transformPage(in, MathUtils.floatToSubtract(1, positionOffset));
        mPageTransformer.transformPage(out, MathUtils.floatToSubtract(0, positionOffset));
    }

    private int getRealSlidState() {
        if (mItemPosOffset == 1) {
            return SLID_NONE;
        }
        if (mCurrentState != PageSlider.SLIDING_STATE_IDLE) {
            if (mItemPosOffsetPixels > 0) {
                return SLID_LEFT;
            } else if (mItemPosOffsetPixels < 0) {
                return SLID_RIGHT;
            }
        } else {
            if (mItemPosOffsetPixels > 0) {
                return SLID_LEFT_ELASTIC;
            } else if (mItemPosOffsetPixels < 0) {
                return SLID_RIGHT_ELASTIC;
            }
        }
        return SLID_NONE;
    }

    /**
     * PageSlide的动画接口
     *
     * @since 2021-04-12
     */
    public interface PageTransformer {
        /**
         * 动画接口
         *
         * @param page 子组件
         * @param position position
         */
        void transformPage(Component page, float position);
    }
}
